/**
 * 
 */
package cn.ad.server.web.servlet.v2.requesthandler;

import cn.ad.server.web.log.entity.AdActiveEventLog;
import cn.ad.server.web.servlet.v2.parser.AdRequestParseException;
import cn.ad.server.web.servlet.v2.parser.HttpServletParser;
import cn.ad.server.web.servlet.v2.parser.HttpServletParserAdapter;
import cn.ad.server.web.servlet.v2.parser.ParameterParseExcption;
import cn.ad.server.web.spring.model.*;
import cn.ad.server.web.spring.model.dactive.DactiveAdResponse;
import cn.ad.server.web.spring.service.actions.RequestActionException;
import cn.ad.server.domain.enumration.ResponseStatusCode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 *	回调激活处理。
 * @author wangwei
 */
public abstract class DactiveRequestHandler extends AdRequestHandler{
	
	private static Logger LOGGER = LoggerFactory.getLogger(DactiveRequestHandler.class);
	
	/**
	 * 接入渠道消息解析，针对特定渠道的请求消息解析
	 */
	protected Map<String, HttpServletParserAdapter> channelRequestParsers;
	
	
	protected final ObjectMapper objectMapper = new ObjectMapper();
	
	/**
	 * 
	 */
	public DactiveRequestHandler() {
		channelRequestParsers = new HashMap<>();
	}

	/* (non-Javadoc)
	 * @see cn.falconnect.adserver.adapter.ServletRequestHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response)  throws RequestHandleException{
		AdRequest activeReq= null;
		DactiveAdResponse  activeRes = null;
		IAdserverRequest adReq = null;
		try{
			String channel = getChannel(request);
			String avid = getAvid(request);
			if(StringUtils.isAnyEmpty(channel)&&StringUtils.isAnyEmpty(avid)){
				throw new RequestHandleException("无法获取请求中的接入渠道标识或DSP广告主标识.");
			}
			HttpServletParser parser =getParser();

			if(parser == null){
				throw new NullPointerException("servletParser is null.");
			}
			//解析请求参数
			adReq = parser.parse(request);

			if(adReq == null){
				throw new AdRequestParseException("AdRequest is null.");
			}
			
			if(adReq instanceof AvidRequest){
				activeReq =  (AdRequest)adReq;
				activeReq.setChannelID(avid);
				activeReq.setAvid(avid);
			}else if(adReq instanceof AdRequest){
				activeReq =  (AdRequest)adReq;
				activeReq.setChannelID(channel);
			}else{
				throw new RequestHandleException("The Request is not support. class:" + adReq.getClass().getName());
			}
			//验证请求对象
			validRequest(adReq);
			//逻辑处理。
			activeRes = (DactiveAdResponse)doHandle((AdRequest)adReq);
			//处理响应。
			handleResponse(request, response, parser, activeReq, activeRes);
			//TODO 测试用。
			LOGGER.info("激活回调成功,参数：" + adReq.toString()+" 补量渠道id="+ activeRes.getFillChannelId());
		}catch(ParameterParseExcption ex){
			activeRes = createExceptionResponse(activeRes, ResponseStatusCode.INVALID_REQ_PARAMETER);
			handleExceptionResponse(request, response, activeReq, activeRes);
			LOGGER.warn("解析激活回调接口参数 [{} = {}]出现异常:" + ex.getMessage(), ex.getParamName(), ex.getParamValue(), ex);
		}catch(AdRequestParseException ex){
			activeRes = createExceptionResponse(activeRes, ResponseStatusCode.INVALID_REQ_PARAMETER);
			handleExceptionResponse(request, response, activeReq, activeRes);
			throw new RequestHandleException("请求消息解析出现异常.", ex);
		}catch(RequestParamValidFailedException e){
			activeRes = createExceptionResponse(activeRes, ResponseStatusCode.INVALID_REQ_PARAMETER);
			handleExceptionResponse(request, response, activeReq, activeRes);
			throw new RequestHandleException("广告激活回调请求参数验证失败," + e.getMessage());
		}catch(Exception e){
			LOGGER.error("广告激活回调请求处理异常，系统内部错误:{}", e.getMessage(), e.getCause(),e);
			activeRes = createExceptionResponse(activeRes, ResponseStatusCode.UNKNOWN_INNER_ERROR);
			handleExceptionResponse(request, response, activeReq, activeRes);
		}finally {
			logDactive(activeReq, activeRes);
		}
	}
	
	/**
	 * 处理响应
	 * @param request
	 * @param response
	 * @param selvetParser
	 * @param adRequest
	 * @param adResponse
	 * @throws Exception
	 */
	public void handleResponse(HttpServletRequest request, HttpServletResponse response, HttpServletParser selvetParser, IAdserverRequest adRequest, IAdserverResponse adResponse) throws Exception {
		selvetParser.writeResponse(adRequest, adResponse, request, response);
	}
	
	/**
	 * 处理异常响应
	 * @param request
	 * @param response
	 * @param adRequest
	 * @param adResponse
	 */
	public void handleExceptionResponse(HttpServletRequest request, HttpServletResponse response, IAdserverRequest adRequest, IAdserverResponse adResponse){
		try {
			if(adResponse instanceof DactiveAdResponse){
				response.setContentType("application/json;charset=utf-8");
				DactiveAdResponse res = (DactiveAdResponse)adResponse;
				AdResponse msRes = res.getAdReponse();
				ServletOutputStream outputStream = response.getOutputStream();
				objectMapper.writeValue(outputStream, msRes);
			}
		} catch (Exception e) {
			LOGGER.error("广告激活回调响应处理异常，系统内部错误:{}", e.getMessage(), e.getCause(),e);
		}
		response.setHeader("Connection", "close");
	}
	
	
	/**
	 * 生成异常响应
	 * @param srcRes 原来的处理响应
	 * @param reStatusCode 异常状态
	 * @return
	 */
	private DactiveAdResponse createExceptionResponse(DactiveAdResponse srcRes, ResponseStatusCode reStatusCode){
		DactiveAdResponse res = srcRes != null ? srcRes : (new DactiveAdResponse());
		res.setStatus(reStatusCode.value());
		res.setMessage(reStatusCode.getMessage());
		return res;
	}

	/**
	 * 记录激活回调请求处理日志
	 * @param req
	 */
	public void logDactive(AdRequest req, DactiveAdResponse res){
		if(req == null || res == null){
			return;
		}
		AdActiveEventLog eventLog = populate(req, res);
		logAdserverEventLog(eventLog);
	}
	
	/**
	 * 填充log记录对象
	 * 
	 * @param req
	 * @param res
	 * @return
	 */
	public abstract AdActiveEventLog populate(AdRequest req, DactiveAdResponse res);
	
	
	/**
	 * 逻辑处理
	 * @param impressionReq
	 * @param cp
	 * @return 
	 * @throws RequestActionException 
	 */
	public AdResponse doHandle(AdRequest request) throws RequestActionException{
		return getRequestAction().doRequest(request);
	}
	
	
	/**
	 * 获取广告激活回调事件请求消息解析器
	 * @param channelID 渠道标识
	 * @return
	 */
	public HttpServletParserAdapter getRequestParser(String channelID){
		if(channelRequestParsers == null){
			return null;
		}
		return channelRequestParsers.get(channelID);
	}


	/**
	 * @return the channelRequestParsers
	 */
	public Map<String, HttpServletParserAdapter> getChannelRequestParsers() {
		return channelRequestParsers;
	}

	/**
	 * @param channelRequestParsers the channelRequestParsers to set
	 */
	public void setChannelRequestParsers(Map<String, HttpServletParserAdapter> channelRequestParsers) {
		this.channelRequestParsers = channelRequestParsers;
	}

}
